GDK W32: Handle maximizing correctly for small primary monitors
authorРуслан Ижбулатов <lrn1986@gmail.com>
Sun, 11 Dec 2016 16:26:34 +0000 (16:26 +0000)
committerРуслан Ижбулатов <lrn1986@gmail.com>
Sat, 2 Dec 2017 10:38:17 +0000 (10:38 +0000)
When primary monitor is smaller than the actual monitor on which the
window is being maximized, the WM will do widnow size adjustments
that will completely screw the window size if we try to make it
smaller than 100% fullscreen (to account for taskbar size, for example).

Fix this by overriding maximized window size during WM_WINDOWPOSCHANGING.

https://bugzilla.gnome.org/show_bug.cgi?id=775808

gdk/win32/gdkevents-win32.c
gdk/win32/gdkwindow-win32.c
gdk/win32/gdkwindow-win32.h

index 75fe1643400d9f3df33f48e0803a32d704fd7afc..e35c3847623ade7ce4f53161500409860315834c 100644 (file)
@@ -2078,6 +2078,25 @@ _gdk_win32_window_fill_min_max_info (GdkWindow  *window,
     }
   else
     {
+      /* According to "How does the window manager adjust ptMaxSize and
+       * ptMaxPosition for multiple monitors?" article
+       * https://blogs.msdn.microsoft.com/oldnewthing/20150501-00/?p=44964
+       * if ptMaxSize >= primary_monitor_size, then it will be adjusted by
+       * WM to account for the monitor size differences if the window gets
+       * maximized on a non-primary monitor, by simply adding the size
+       * difference (i.e. if non-primary monitor is larger by 100px, then
+       * window will be made larger exactly by 100px).
+       * If ptMaxSize < primary_monitor_size at least in one direction,
+       * nothing is adjusted.
+       * Therefore, if primary monitor is smaller than the actual monitor,
+       * then it is not possible to give window a size that is larger than
+       * the primary monitor and smaller than the non-primary monitor,
+       * because WM will always enlarge the window.
+       * Therefore, it is impossible to account for taskbar size.
+       * So we don't try at all. Instead we just remember that we're trying
+       * to maximize the window, catch WM_WINDOWPOSCHANGING and
+       * adjust the size then.
+       */
       HMONITOR nearest_monitor;
       MONITORINFO nearest_info;
 
@@ -3108,6 +3127,10 @@ gdk_event_translate (MSG  *msg,
        case SC_RESTORE:
          do_show_window (window, msg->wParam == SC_MINIMIZE ? TRUE : FALSE);
          break;
+        case SC_MAXIMIZE:
+          impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+          impl->maximizing = TRUE;
+         break;
        }
 
       break;
@@ -3159,7 +3182,26 @@ gdk_event_translate (MSG  *msg,
                                  GetNextWindow (msg->hwnd, GW_HWNDPREV))));
 
       if (GDK_WINDOW_IS_MAPPED (window))
-       return_val = ensure_stacking_on_window_pos_changing (msg, window);
+        {
+         return_val = ensure_stacking_on_window_pos_changing (msg, window);
+
+          impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+          if (impl->maximizing)
+            {
+              MINMAXINFO our_mmi;
+
+              if (_gdk_win32_window_fill_min_max_info (window, &our_mmi))
+                {
+                  windowpos = (WINDOWPOS *) msg->lParam;
+                  windowpos->cx = our_mmi.ptMaxSize.x;
+                  windowpos->cy = our_mmi.ptMaxSize.y;
+                }
+
+              impl->maximizing = FALSE;
+            }
+        }
+
       break;
 
     case WM_WINDOWPOSCHANGED:
index 9f62065ca57fcaea25c22c21fd7d52768237d425..2c4a4ee6abf994ae3230a3dd00d4ee33ff4ed5ce 100644 (file)
@@ -5677,6 +5677,10 @@ GtkShowWindow (GdkWindow *window,
       break;
     }
 
+  /* Ensure that maximized window size is corrected later on */
+  if (cmd_show == SW_MAXIMIZE)
+    impl->maximizing = TRUE;
+
   return ShowWindow (hwnd, cmd_show);
 }
 
index 55928bceba8e99f88ab3fa83cd6670e3e0bc14fd..101b23f8274c80aa1d24aba36705ccb62fd1e18e 100644 (file)
@@ -285,6 +285,12 @@ struct _GdkWindowImplWin32
    */
   guint have_temp_styles : 1;
 
+  /* If TRUE, the window is in the process of being maximized.
+   * This is set by WM_SYSCOMMAND and by gdk_win32_window_maximize (),
+   * and is unset when WM_WINDOWPOSCHANGING is handled.
+   */
+  guint maximizing : 1;
+
   /* GDK does not keep window contents around, it just draws new
    * stuff over the window where changes occurred.
    * cache_surface retains old window contents, because